/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   Module Name          : com.yaodian100.ec.member.service.impl.AddressServiceImpl
   Module Description   :

   Date Created      : 2009/12/23
   Original Author   : feeling.wang
   Team              : yaodian100
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   MODIFICATION HISTORY
   ------------------------------------------------------------------------------
   Date Modified       Modified by       Comments
   ------------------------------------------------------------------------------
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
package com.yaodian100.ec.member.service.impl;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.common.dao.ObjectDao;
import com.yaodian100.core.common.dao.impl.CommonCriteria;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.common.service.BaseManager;
import com.yaodian100.core.common.service.impl.DomainServiceImpl;
import com.yaodian100.core.common.utils.ServerValue;
import com.yaodian100.core.menu.entity.Menu;
import com.yaodian100.core.menu.entity.Option;
import com.yaodian100.core.menu.service.MenuService;
import com.yaodian100.ec.campaign.entity.CampaignDiscount;
import com.yaodian100.ec.campaign.service.CampaignDiscountService;
import com.yaodian100.ec.member.entity.City;
import com.yaodian100.ec.member.entity.District;
import com.yaodian100.ec.member.entity.Province;
import com.yaodian100.ec.member.service.AddessService;
import com.yaodian100.ec.tmall.entity.AddrMapping;

/**
 * @author feeling.wang
 * 
 */
public class AddressServiceImpl extends DomainServiceImpl<Province> implements AddessService, InitializingBean {
	private ObjectDao<City> cityDao;
	private ObjectDao<District> districtDao;
	private MenuService menuService;
	@Autowired
	private BaseManager baseManager;
	@Autowired
	private JdbcTemplate jdbcTemplate;
	private HashMap<String, String> codMap;
	private HashMap freightMap;
	private HashMap<String, String> provinceMap;
	// private int freightBase = 3; //改成动态抓取
	@Autowired
	private CampaignDiscountService campaignDiscountService;

	@Override
	public void afterPropertiesSet() throws Exception {
		setCodData();
		setProvinceData();
		setFreight();
	}

	@Override
	@Transactional(readOnly = false)
	public void deleteCity(City city) throws CoreException {
		cityDao.delete(city);
	}

	@Override
	@Transactional(readOnly = false)
	public void deleteDistrict(District district) throws CoreException {
		districtDao.delete(district);
	}

	@Override
	public void generateAddress() throws CoreException, Exception {
		List<Province> provinces = getAllProvinceList();
		List<City> citys = null;
		List<District> districts = null;
		CommonCriteria crit = null;
		StringBuilder provinceSb = new StringBuilder("");
		StringBuilder citySb = new StringBuilder("");
		StringBuilder districtSb = new StringBuilder("");
		String provinceArray;
		String cityArray;
		String districtArray;
		provinceSb.append("var provinceArray = [");
		citySb.append("var cityArray = [");
		districtSb.append("var districtArray = [");
		for (Province province : provinces) {
			// 省
			provinceSb.append("{'When': '").append(province.getName()).append("' ,'Value':'").append(province.getName())
					.append("', 'Text' : '").append(province.getName()).append("'}");

			// 城市
			crit = new CommonCriteria();
			crit.addEq("provinceId", province.getId().intValue());
			crit.addEq("isDelete", "N");
			citys = getCityList(crit);
			for (City city : citys) {
				citySb.append("{'When': '").append(province.getName()).append("' ,'Value':'").append(city.getName())
						.append("', 'Text' : '").append(city.getName()).append("'}");
				citySb.append(",");

				// 地區
				crit = new CommonCriteria();
				crit.addEq("cityId", city.getId().intValue());
				crit.addEq("isDelete", "N");
				districts = getDistrictList(crit);
				for (District district : districts) {
					districtSb.append("{'When': '").append(city.getName()).append("' ,'Value':'").append(district.getName())
							.append("', 'Text' : '").append(district.getName()).append("'}");
					districtSb.append(",");
				}
			}
			provinceSb.append(",");
		}
		provinceArray = provinceSb.substring(0, provinceSb.length() - 1) + "];";
		cityArray = citySb.substring(0, citySb.length() - 1) + "];";
		districtArray = districtSb.substring(0, districtSb.length() - 1) + "];";
		StringBuilder outFile = new StringBuilder("");
		outFile.append(provinceArray).append(cityArray).append(districtArray);
		mkdir("genJS");
		File file = new File(ServerValue.getFrontApachePath() + "genJS" + File.separator + "yaodian_zipcode.js");
		FileUtils.writeStringToFile(file, outFile.toString());
		outFile.setLength(0);
		provinceSb.setLength(0);
		citySb.setLength(0);
		districtSb.setLength(0);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void generateAddressV2() throws CoreException, Exception {
		StringBuilder sb = new StringBuilder("");
		sb.append("select distinct to_province from ec_delivery_rule ");
		List<String> provinces = getDao().getSQLQueryByList(sb.toString(), null, 0, -1);
		List<String> citys = null;
		List<String> districts = null;

		StringBuilder provinceSb = new StringBuilder("");
		StringBuilder citySb = new StringBuilder("");
		StringBuilder districtSb = new StringBuilder("");
		String provinceArray;
		String cityArray;
		String districtArray;
		provinceSb.append("var provinceArray = [");
		citySb.append("var cityArray = [");
		districtSb.append("var districtArray = [");

		List<String> attrs;
		for (String province : provinces) {
			// 省
			provinceSb.append("{'When': '").append(province).append("' ,'Value':'").append(province).append("', 'Text' : '")
					.append(province).append("'}");

			// 城市
			sb = new StringBuilder("");
			sb.append("select distinct to_city from ec_delivery_rule where to_province = ? ");
			attrs = new ArrayList();
			attrs.add(province);
			citys = getDao().getSQLQueryByList(sb.toString(), attrs, 0, -1);
			for (String city : citys) {
				citySb.append("{'When': '").append(province).append("' ,'Value':'").append(city).append("', 'Text' : '")
						.append(city).append("'}");
				citySb.append(",");

				// 地區
				sb = new StringBuilder("");
				sb.append("select distinct to_district from ec_delivery_rule where to_city = ? ");
				attrs = new ArrayList();
				attrs.add(city);
				districts = getDao().getSQLQueryByList(sb.toString(), attrs, 0, -1);
				for (String district : districts) {
					districtSb.append("{'When': '").append(city).append("' ,'Value':'").append(district).append("', 'Text' : '")
							.append(district).append("'}");
					districtSb.append(",");
				}
			}
			provinceSb.append(",");
		}
		provinceArray = provinceSb.substring(0, provinceSb.length() - 1) + "];";
		cityArray = citySb.substring(0, citySb.length() - 1) + "];";
		districtArray = districtSb.substring(0, districtSb.length() - 1) + "];";
		StringBuilder outFile = new StringBuilder("");
		outFile.append(provinceArray).append(cityArray).append(districtArray);
		mkdir("genJS");
		File file = new File(ServerValue.getFrontApachePath() + "genJS" + File.separator + "yaodian_zipcode.js");
		FileUtils.writeStringToFile(file, outFile.toString());
		outFile.setLength(0);
		provinceSb.setLength(0);
		citySb.setLength(0);
		districtSb.setLength(0);
	}

	@Override
	public void generateAddressForMidend() throws CoreException, Exception {
		String sortOrder[] = { "showSeq asc" };
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("isDelete", "N");
		List<Province> provinces = getDao().getList(crit, sortOrder);
		List<City> citys = null;
		List<District> districts = null;
		StringBuilder provinceSb = new StringBuilder("");
		StringBuilder citySb = new StringBuilder("");
		StringBuilder districtSb = new StringBuilder("");
		String provinceArray;
		String cityArray;
		String districtArray;
		provinceSb.append("var provinceArray = [");
		citySb.append("var cityArray = [");
		districtSb.append("var districtArray = [");
		for (Province province : provinces) {
			// 省
			provinceSb.append("{'When': '").append(province.getName()).append("' ,'Value':'").append(province.getName())
					.append("', 'Text' : '").append(province.getName()).append("'}");

			// 城市
			crit = new CommonCriteria();
			crit.addEq("provinceId", province.getId().intValue());
			crit.addEq("isDelete", "N");
			citys = getCityList(crit);
			for (City city : citys) {
				citySb.append("{'When': '").append(province.getName()).append("' ,'Value':'").append(city.getName())
						.append("', 'Text' : '").append(city.getName()).append("'}");
				citySb.append(",");

				// 地區
				crit = new CommonCriteria();
				crit.addEq("cityId", city.getId().intValue());
				crit.addEq("isDelete", "N");
				districts = getDistrictList(crit);
				for (District district : districts) {
					districtSb.append("{'When': '").append(city.getName()).append("' ,'Value':'").append(district.getName())
							.append("', 'Text' : '").append(district.getName()).append("'}");
					districtSb.append(",");
				}
			}
			provinceSb.append(",");
		}
		provinceArray = provinceSb.substring(0, provinceSb.length() - 1) + "];";
		cityArray = citySb.substring(0, citySb.length() - 1) + "];";
		districtArray = districtSb.substring(0, districtSb.length() - 1) + "];";
		StringBuilder outFile = new StringBuilder("");
		outFile.append(provinceArray).append(cityArray).append(districtArray);
		mkdir("genJS");
		File file = new File(ServerValue.getFrontApachePath() + "genJS" + File.separator + "yaodian_zipcodeMidend.js");
		FileUtils.writeStringToFile(file, outFile.toString());
		outFile.setLength(0);
		provinceSb.setLength(0);
		citySb.setLength(0);
		districtSb.setLength(0);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.AddessService#generateAddressForCod()
	 */
	@Override
	public void generateAddressForCod() throws CoreException, Exception {
		List<Province> provinces = getAllProvinceList();
		List<City> citys = null;
		List<District> districts = null;
		CommonCriteria crit = null;
		StringBuilder provinceSb = new StringBuilder("");
		StringBuilder citySb = new StringBuilder("");
		StringBuilder districtSb = new StringBuilder("");
		String provinceArray;
		String cityArray;
		String districtArray;
		provinceSb.append("var provinceArray = [");
		citySb.append("var cityArray = [");
		districtSb.append("var districtArray = [");
		for (Province province : provinces) {
			// 省
			provinceSb.append("{'When': '").append(province.getName()).append("' ,'Value':'").append(province.getName())
					.append("', 'Text' : '").append(province.getName()).append("'}");

			// 城市
			crit = new CommonCriteria();
			crit.addEq("provinceId", province.getId().intValue());
			citys = getCityList(crit);
			for (City city : citys) {
				citySb.append("{'When': '").append(province.getName()).append("' ,'Value':'").append(city.getName())
						.append("', 'Text' : '").append(city.getName()).append("'}");
				citySb.append(",");

				// 地區
				crit = new CommonCriteria();
				crit.addEq("cityId", city.getId().intValue());
				districts = getDistrictList(crit);
				for (District district : districts) {
					if (district.getIsCod().equals("Y")) {
						districtSb.append("{'When': '").append(city.getName()).append("' ,'Value':'").append(district.getName())
								.append("', 'Text' : '※").append(district.getName()).append("'}");
						districtSb.append(",");
					} else {
						districtSb.append("{'When': '").append(city.getName()).append("' ,'Value':'").append(district.getName())
								.append("', 'Text' : '").append(district.getName()).append("'}");
						districtSb.append(",");
					}
				}
			}
			provinceSb.append(",");
		}
		provinceArray = provinceSb.substring(0, provinceSb.length() - 1) + "];";
		cityArray = citySb.substring(0, citySb.length() - 1) + "];";
		districtArray = districtSb.substring(0, districtSb.length() - 1) + "];";
		StringBuilder outFile = new StringBuilder("");
		outFile.append(provinceArray).append(cityArray).append(districtArray);
		mkdir("genJS");
		File file = new File(ServerValue.getFrontApachePath() + "genJS" + File.separator + "yaodian_zipCodCode.js");
		FileUtils.writeStringToFile(file, outFile.toString());
		outFile.setLength(0);
		provinceSb.setLength(0);
		citySb.setLength(0);
		districtSb.setLength(0);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.AddessService#getAllProvinceList()
	 */
	@Override
	public List<Province> getAllProvinceList() throws CoreException {
		String sortOrder[] = { "showSeq asc" };
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("isDelete", "N");
		crit.addEq("isFrontend", "Y");
		List<Province> provinces = getDao().getList(crit, sortOrder);
		return provinces;
	}

	@Override
	public List<Province> getProvinceListByShipExpenseRank(String shipExpenseRank) throws CoreException {
		String sortOrder[] = { "showSeq asc" };
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("isDelete", "N");
		crit.addEq("isFrontend", "Y");
		crit.addEq("shipExpenseRank", shipExpenseRank);
		List<Province> provinces = getDao().getList(crit, sortOrder);
		return provinces;
	}

	@Override
	public City getCity(String name) throws CoreException {
		City city = cityDao.getSingle("name", name);
		return city;
	}

	public ObjectDao<City> getCityDao() {
		return cityDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.AddessService#getCityList(java.lang.String)
	 */
	@Override
	public List<City> getCityList(CommonCriteria crit) throws CoreException {
		String sortOrder[] = { "showSeq asc" };
		List<City> citys = getCityDao().getList(crit, sortOrder);
		return citys;
	}

	public HashMap<String, String> getCodMap() {
		return codMap;
	}

	@Override
	public District getDistrict(String name) throws CoreException {
		District district = districtDao.getSingle("name", name);
		return district;
	}

	public ObjectDao<District> getDistrictDao() {
		return districtDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.AddessService#getDistrictList(java.lang.String)
	 */
	@Override
	public List<District> getDistrictList(CommonCriteria crit) throws CoreException {
		String sortOrder[] = { "showSeq asc" };
		List<District> districts = getDistrictDao().getList(crit, sortOrder);
		return districts;
	}

	@Override
	public BigDecimal getCodFee() {
		BigDecimal codFee = (new BigDecimal("0")).setScale(0);
		try {
			Option shipOption = (Option) freightMap.get("COD");
			codFee = new BigDecimal(shipOption.getMemo1()).setScale(0);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return codFee;
	}

	@Override
	public BigDecimal getDaphneFee() {
		BigDecimal codFee = (new BigDecimal("0")).setScale(0);
		try {
			Option shipOption = (Option) freightMap.get("DAPHNE");
			codFee = new BigDecimal(shipOption.getMemo1()).setScale(0);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return codFee;
	}

	// 原本的运费计算方式，用商品总额来计算，不扣折扣，因此传0进去
	public BigDecimal getFreight(String provinceName, BigDecimal weight, BigDecimal orderAmount) {
		return getFreight(provinceName, weight, orderAmount, BigDecimal.ZERO);
	}

	@Override
	// 现形的运费计算方式：商品总额-折扣
	public BigDecimal getFreight(String provinceName, BigDecimal weight, BigDecimal orderAmount, BigDecimal discount) {
		BigDecimal freight = BigDecimal.ZERO;
		BigDecimal discountFreight = BigDecimal.ZERO;
		try {
			String shipExpenseRank = provinceMap.get(provinceName);
			Option shipOption = (Option) freightMap.get(shipExpenseRank);
			// 計算優惠運費
			CampaignDiscount cd = campaignDiscountService.getByOrderAmount(orderAmount.subtract(discount), null);
			if (cd != null) {
				String[] allowShipExpenseRank = StringUtils.split(
						StringUtils.defaultString(cd.getShipExpenseRank(), "1,1,1,1,1,1"), ",");
				if ("1".equals(allowShipExpenseRank[Integer.parseInt(shipExpenseRank) - 1])) { // shipExpenseRank 起始值为 1
					// ，但陈列起始值为 0 ，所以要减1
					BigDecimal w = new BigDecimal(cd.getDiscountData());
					if (w.intValue() <= ServerValue.getFreightBase()) { // 基本费率
						discountFreight = new BigDecimal(shipOption.getMemo1()).setScale(0);
					} else {
						int extraFare = (w.intValue() - ServerValue.getFreightBase()) * Integer.parseInt(shipOption.getMemo2());
						discountFreight = new BigDecimal(shipOption.getMemo1()).setScale(0);
						discountFreight = discountFreight.add(new BigDecimal(extraFare).setScale(0));
					}
				}
			}

			// 計算原始運費
			weight = weight.divide(new BigDecimal("1000"), 0, BigDecimal.ROUND_UP);
			if (weight.intValue() <= ServerValue.getFreightBase()) { // 基本费率
				freight = new BigDecimal(shipOption.getMemo1()).setScale(0);
			} else {
				int extraFare = (weight.intValue() - ServerValue.getFreightBase()) * Integer.parseInt(shipOption.getMemo2());
				freight = new BigDecimal(shipOption.getMemo1()).setScale(0);
				freight = freight.add(new BigDecimal(extraFare).setScale(0));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		freight = freight.subtract(discountFreight);
		if (BigDecimal.ZERO.equals(freight.max(BigDecimal.ZERO))) {
			// 若優惠運費大於原始運費, 運費為零
			freight = BigDecimal.ZERO;
		}
		return freight;
	}

	public int getFreightBase() {
		return ServerValue.getFreightBase();
	}

	public HashMap getFreightMap() {
		return freightMap;
	}

	public MenuService getMenuService() {
		return menuService;
	}

	public HashMap<String, String> getProvinceMap() {
		return provinceMap;
	}

	@Override
	public boolean isCod(String city, String district) {
		try {
			return "Y".equals(codMap.get(city + district));
		} catch (Exception e) {
			return false;
		}
	}

	void mkdir(String folderName) {
		File folder = new File(ServerValue.getFrontApachePath() + File.separator + folderName);
		if (!folder.exists()) {
			folder.mkdirs();
		}
	}

	@Override
	@Transactional(readOnly = false)
	public void saveCity(City city) throws CoreException {
		cityDao.save(city);
	}

	@Override
	@Transactional(readOnly = false)
	public void saveDistrict(District district) throws CoreException {
		districtDao.save(district);
	}

	public void setCityDao(ObjectDao<City> cityDao) {
		this.cityDao = cityDao;
	}

	/**
	 * setCod Map
	 * 
	 * @throws CoreException
	 */
	@Override
	public void setCodData() throws CoreException {
		if (codMap == null) {
			codMap = new HashMap();
		}
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("isCod", "Y");
		List districtList = getDistrictList(crit);
		for (Iterator i = districtList.iterator(); i.hasNext();) {
			District p = (District) i.next();
			codMap.put(p.getCityName() + p.getName(), "Y");
		}
	}

	public void setCodMap(HashMap<String, String> codMap) {
		this.codMap = codMap;
	}

	public void setDistrictDao(ObjectDao<District> districtDao) {
		this.districtDao = districtDao;
	}

	/**
	 * setCod Map
	 * 
	 * @throws CoreException
	 */
	@Override
	public void setFreight() throws CoreException {
		if (freightMap == null) {
			freightMap = new HashMap();
		}

		Menu menu = menuService.get("Freight.key");
		Map<String, Option> option = menu.getOptions();
		Set<String> keySet = option.keySet();
		for (Iterator i = keySet.iterator(); i.hasNext();) {
			String key = (String) i.next();
			freightMap.put(key, option.get(key));
		}
	}

	public void setFreightMap(HashMap freightMap) {
		this.freightMap = freightMap;
	}

	public void setMenuService(MenuService menuService) {
		this.menuService = menuService;
	}

	@Override
	public void setProvinceData() throws CoreException {
		if (provinceMap == null) {
			provinceMap = new HashMap();
		}
		List provinceList = getAllProvinceList();
		for (Iterator i = provinceList.iterator(); i.hasNext();) {
			Province p = (Province) i.next();
			provinceMap.put(p.getName(), p.getShipExpenseRank());
		}
	}

	public void setProvinceMap(HashMap<String, String> provinceMap) {
		this.provinceMap = provinceMap;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.AddessService#generateAddress()
	 */
	@Override
	@Transactional(readOnly = false)
	public void updateCity(City city) throws CoreException {
		cityDao.update(city);
	}

	@Override
	@Transactional(readOnly = false)
	public void updateDistrict(District district) throws CoreException {
		districtDao.update(district);
	}

	@Override
	public void generateAddressForServiceSupport() throws CoreException, Exception {
		List<Province> provinces = getAllProvinceList();
		List<City> citys = null;
		List<District> districts = null;
		CommonCriteria crit = null;
		StringBuilder districtSb = new StringBuilder("");
		String districtArray;
		districtSb.append("var districtSvieArray = [ ");
		// 地區
		crit = new CommonCriteria();
		districts = getDistrictList(crit);
		for (District district : districts) {
			if (district.getIsCod().equals("Y") && StringUtils.isNotBlank(district.getNonServiceSupport())
					&& StringUtils.isNotBlank(district.getServiceSupport())) {
				districtSb.append("{'When': '").append(district.getName()).append("' ,'Value':'")
						.append(district.getServiceSupport().replaceAll("\n", "")).append("', 'Text' : '")
						.append(district.getNonServiceSupport().replaceAll("\n", "")).append("'}");
				districtSb.append(",");
			}
		}
		districtArray = districtSb.substring(0, districtSb.length() - 1) + "];";
		StringBuilder outFile = new StringBuilder("");
		outFile.append(districtArray);
		mkdir("genJS");
		File file = new File(ServerValue.getFrontApachePath() + "genJS" + File.separator + "yaodian_zipSevice.js");
		FileUtils.writeStringToFile(file, outFile.toString());
		outFile.setLength(0);
		districtSb.setLength(0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.AddessService#convertAddr(java.lang.String, java.lang.String,
	 * java.lang.String, java.lang.String)
	 */
	@Override
	public AddrMapping convertAddr(String province, String city, String county, String memo) {
		AddrMapping result = null;
		Object[] addrs = null;
		if ("上海".equals(province) || "北京".equals(province)) {
			addrs = baseManager.customHqlQuery("from AddrMapping where outProvince=? and outCity=?", new Object[] { province,
					city });
		} else {
			addrs = baseManager.customHqlQuery("from AddrMapping where outProvince=? and outCity=? and outDistrict=?",
					new Object[] { province, city, county });
		}
		if ((addrs == null) || (addrs.length == 0)) {
			result = new AddrMapping();
			result.setOutProvince(province);
			result.setOutCity(city);
			result.setOutDistrict(county);
			result.setYdProvince(province);
			result.setYdCity(city);
			result.setYdDistrict(county);
			String sql = "insert into EC_ADDR_MAPPING_TMP(OUT_PROVINCE, OUT_CITY, OUT_DISTRICT, OUT_ADDR, DOMAIN_SRC) values(?,?,?,?,?)";
			jdbcTemplate.update(sql, province, city, county, memo, null);
		} else {
			result = (AddrMapping) addrs[0];
		}
		return result;
	}

}